#include <QDir>
#include <QPluginLoader>
#include "notificationmanager.h"
#include <QSettings>
#include "notificationnewmessages.h"
#include "log.h"
#include "paths.h"

namespace Wishmaster
{
	NotificationManager::NotificationManager(QObject *parent) :
		QObject(parent), Singleton<NotificationManager>()
	{
		m_factories.clear();
		if(loadPluginsFromDirectory("./plugins/notificators") ||
		   loadPluginsFromDirectory("../plugins/notificators")) // Try to find plugins from build directory first
			return;
		if(!loadPluginsFromDirectory(DefaultPath::notificatorPlugins()))
		{
			log(llError, "Unable to find notificator plugins");
		}

		QSettings settings;
		QString notificator = settings.value("interface/notification/notificator").toString();
		if(!notificator.isEmpty())
			setActiveNotificator(notificator);
		else
		{
			QString defaultNotificator = getDefaultNotificator();
		}

		m_player = new Phonon::MediaObject(this);
		m_playSound = settings.value("interface/notification/playsound", true).toBool();
		m_output = new Phonon::AudioOutput(Phonon::NotificationCategory);
		Phonon::createPath(m_player, m_output);
	}

	NotificationManager::~NotificationManager()
	{
		QSettings settings;
		settings.setValue("interface/notification/playsound", isPlaySounds());

		delete m_player;
		delete m_output;
	}

	void NotificationManager::emitNotification(const Notification& notification)
	{
		if(!m_notificator)
			return;
		m_notificator->notify(notification);
		if(isPlaySounds() && !notification.soundFile().isEmpty())
		{
			m_player->setCurrentSource(notification.soundFile());
			m_player->play();
		}
	}

	void NotificationManager::newMessagesNotification(const QString& text)
	{
		if(!m_notificator)
			return;
		NotificationNewMessages notification(text);
		emitNotification(notification);
	}

	bool NotificationManager::loadPluginsFromDirectory(const QString& pluginDirectory)
	{
		log(llNormal, "Loading notificator from directory: %s", qPrintable(pluginDirectory));
		bool found = false;
		QDir dir(pluginDirectory);
		foreach(const QString& filename, dir.entryList(QDir::Files))
		{
			log(llDebug, "Trying to load: %s", qPrintable(filename));
			QPluginLoader loader(dir.absoluteFilePath(filename));
			if(loader.isLoaded())
				continue;
			QObject* instance = loader.instance();
			if(instance)
			{
				NotificatorFactory* factory = qobject_cast<NotificatorFactory*>(instance);
				if(factory)
				{
					if(factoryLoaded(factory->id()))
						continue;
					found = true;
					log(llNormal, "Loading notificator: %s", qPrintable(factory->id()));
					m_factories.append(QSharedPointer<NotificatorFactory>(factory));
				}
				else
					log(llDebug, "!factory");
			}
			else
				log(llDebug, "!instance: %s", qPrintable(loader.errorString()));
		}
		return found;
	}

	bool NotificationManager::factoryLoaded(const QString& id)
	{
		foreach(const QSharedPointer<NotificatorFactory>& factory, m_factories)
		{
			if(factory->id() == id)
				return true;
		}
		return false;
	}

	QStringList NotificationManager::notificators()
	{
		QStringList notificators;
		foreach(const QSharedPointer<NotificatorFactory>& factory, m_factories)
		{
			notificators.append(factory->id());
		}
		return notificators;
	}

	void NotificationManager::setActiveNotificator(const QString& id)
	{
		foreach(const QSharedPointer<NotificatorFactory>& factory, m_factories)
		{
			if(factory->id() == id)
			{
				m_notificator = factory->createNotificator();
				return;
			}
		}
	}

	QSharedPointer<QWidget> NotificationManager::makeConfig()
	{
		if(!m_notificator)
			return QSharedPointer<QWidget>();
		return m_notificator->makeConfig();
	}

	bool NotificationManager::updateConfig(const QSharedPointer<QWidget>& config)
	{
		if(!m_notificator)
			return false;
		return m_notificator->updateConfig(config);
	}

	void NotificationManager::setPlaySounds(bool playsound)
	{
		m_playSound = playsound;
	}

	bool NotificationManager::isPlaySounds() const
	{
		return m_playSound;
	}

	QString NotificationManager::getDefaultNotificator()
	{
#ifdef WIN32
		return QString("System tray icon");
#else
		return QString("External command");
#endif
	}
}
